<?php
/**
 * Zend Framework
 *
 * LICENSE
 *
 * This source file is subject to the new BSD license that is bundled
 * with this package in the file LICENSE.txt.
 * It is also available through the world-wide-web at this URL:
 * http://framework.zend.com/license/new-bsd
 * If you did not receive a copy of the license and are unable to
 * obtain it through the world-wide-web, please send an email
 * to license@zend.com so we can send you a copy immediately.
 *
 * @category   Zend
 * @package    Zend_Cache
 * @subpackage Zend_Cache_Backend
 * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
 * @license    http://framework.zend.com/license/new-bsd     New BSD License
 * @version    $Id: Backend.php 18951 2009-11-12 16:26:19Z alexander $
 */


/**
 * @package    Zend_Cache
 * @subpackage Zend_Cache_Backend
 * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
 * @license    http://framework.zend.com/license/new-bsd     New BSD License
 */
class Zend_Cache_Backend
{
	/**
	 * Frontend or Core directives
	 *
	 * =====> (int) lifetime :
	 * - Cache lifetime (in seconds)
	 * - If null, the cache is valid forever
	 *
	 * =====> (int) logging :
	 * - if set to true, a logging is activated throw Zend_Log
	 *
	 * @var array directives
	 */
	protected $_directives = array(
        'lifetime' => 3600,
        'logging'  => false,
        'logger'   => null
	);

	/**
	 * Available options
	 *
	 * @var array available options
	 */
	protected $_options = array();

	/**
	 * Constructor
	 *
	 * @param  array $options Associative array of options
	 * @throws Zend_Cache_Exception
	 * @return void
	 */
	public function __construct(array $options = array())
	{
		while (list($name, $value) = each($options)) {
			$this->setOption($name, $value);
		}
	}

	/**
	 * Set the frontend directives
	 *
	 * @param  array $directives Assoc of directives
	 * @throws Zend_Cache_Exception
	 * @return void
	 */
	public function setDirectives($directives)
	{
		if (!is_array($directives)) Zend_Cache::throwException('Directives parameter must be an array');
		while (list($name, $value) = each($directives)) {
			if (!is_string($name)) {
				Zend_Cache::throwException("Incorrect option name : $name");
			}
			$name = strtolower($name);
			if (array_key_exists($name, $this->_directives)) {
				$this->_directives[$name] = $value;
			}

		}

		$this->_loggerSanity();
	}

	/**
	 * Set an option
	 *
	 * @param  string $name
	 * @param  mixed  $value
	 * @throws Zend_Cache_Exception
	 * @return void
	 */
	public function setOption($name, $value)
	{
		if (!is_string($name)) {
			Zend_Cache::throwException("Incorrect option name : $name");
		}
		$name = strtolower($name);
		if (array_key_exists($name, $this->_options)) {
			$this->_options[$name] = $value;
		}
	}

	/**
	 * Get the life time
	 *
	 * if $specificLifetime is not false, the given specific life time is used
	 * else, the global lifetime is used
	 *
	 * @param  int $specificLifetime
	 * @return int Cache life time
	 */
	public function getLifetime($specificLifetime)
	{
		if ($specificLifetime === false) {
			return $this->_directives['lifetime'];
		}
		return $specificLifetime;
	}

	/**
	 * Return true if the automatic cleaning is available for the backend
	 *
	 * DEPRECATED : use getCapabilities() instead
	 *
	 * @deprecated
	 * @return boolean
	 */
	public function isAutomaticCleaningAvailable()
	{
		return true;
	}

	/**
	 * Determine system TMP directory and detect if we have read access
	 *
	 * inspired from Zend_File_Transfer_Adapter_Abstract
	 *
	 * @return string
	 * @throws Zend_Cache_Exception if unable to determine directory
	 */
	public function getTmpDir()
	{
		$tmpdir = array();
		foreach (array($_ENV, $_SERVER) as $tab) {
			foreach (array('TMPDIR', 'TEMP', 'TMP', 'windir', 'SystemRoot') as $key) {
				if (isset($tab[$key])) {
					if (($key == 'windir') or ($key == 'SystemRoot')) {
						$dir = realpath($tab[$key] . '\\temp');
					} else {
						$dir = realpath($tab[$key]);
					}
					if ($this->_isGoodTmpDir($dir)) {
						return $dir;
					}
				}
			}
		}
		$upload = ini_get('upload_tmp_dir');
		if ($upload) {
			$dir = realpath($upload);
			if ($this->_isGoodTmpDir($dir)) {
				return $dir;
			}
		}
		if (function_exists('sys_get_temp_dir')) {
			$dir = sys_get_temp_dir();
			if ($this->_isGoodTmpDir($dir)) {
				return $dir;
			}
		}
		// Attemp to detect by creating a temporary file
		$tempFile = tempnam(md5(uniqid(rand(), TRUE)), '');
		if ($tempFile) {
			$dir = realpath(dirname($tempFile));
			unlink($tempFile);
			if ($this->_isGoodTmpDir($dir)) {
				return $dir;
			}
		}
		if ($this->_isGoodTmpDir('/tmp')) {
			return '/tmp';
		}
		if ($this->_isGoodTmpDir('\\temp')) {
			return '\\temp';
		}
		Zend_Cache::throwException('Could not determine temp directory, please specify a cache_dir manually');
	}

	/**
	 * Verify if the given temporary directory is readable and writable
	 *
	 * @param $dir temporary directory
	 * @return boolean true if the directory is ok
	 */
	protected function _isGoodTmpDir($dir)
	{
		if (is_readable($dir)) {
			if (is_writable($dir)) {
				return true;
			}
		}
		return false;
	}

	/**
	 * Make sure if we enable logging that the Zend_Log class
	 * is available.
	 * Create a default log object if none is set.
	 *
	 * @throws Zend_Cache_Exception
	 * @return void
	 */
	protected function _loggerSanity()
	{
		if (!isset($this->_directives['logging']) || !$this->_directives['logging']) {
			return;
		}
		try {
			/**
			 * @see Zend_Log
			 */
			require_once 'Zend/Log.php';
		} catch (Zend_Exception $e) {
			Zend_Cache::throwException('Logging feature is enabled but the Zend_Log class is not available');
		}
		if (isset($this->_directives['logger'])) {
			if ($this->_directives['logger'] instanceof Zend_Log) {
				return;
			} else {
				Zend_Cache::throwException('Logger object is not an instance of Zend_Log class.');
			}
		}
		// Create a default logger to the standard output stream
		require_once 'Zend/Log/Writer/Stream.php';
		$logger = new Zend_Log(new Zend_Log_Writer_Stream('php://output'));
		$this->_directives['logger'] = $logger;
	}

	/**
	 * Log a message at the WARN (4) priority.
	 *
	 * @param  string $message
	 * @throws Zend_Cache_Exception
	 * @return void
	 */
	protected function _log($message, $priority = 4)
	{
		if (!$this->_directives['logging']) {
			return;
		}

		if (!isset($this->_directives['logger'])) {
			Zend_Cache::throwException('Logging is enabled but logger is not set.');
		}
		$logger = $this->_directives['logger'];
		if (!$logger instanceof Zend_Log) {
			Zend_Cache::throwException('Logger object is not an instance of Zend_Log class.');
		}
		$logger->log($message, $priority);
	}
}
